package org.jugile.jsontmpl.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jugile.util.*;

import org.jugile.jsontmpl.common.*;



public abstract class ObjBase extends Entity {
	static Logger log = Logger.getLogger(ObjBase.class);
	
	public DOH getDoh() { return new DOH("Obj",getId()); }

	public void reindex(Domain d) {}
	
	// --- fields ---

	private String name;
	public String getName() { return name; }
	public Obj setName(String v) { name = v; d()._modified(this); return (Obj)this; }
 	private String desc;
	public String getDesc() { return desc; }
	public Obj setDesc(String v) { desc = v; d()._modified(this); return (Obj)this; }
 	private String fname;
	public String getFname() { return fname; }
	public Obj setFname(String v) { fname = v; d()._modified(this); return (Obj)this; }
 	private String call;
	public String getCall() { return call; }
	public Obj setCall(String v) { call = v; d()._modified(this); return (Obj)this; }
  

 
	// --- connections ---

 
 
 

	// --- 1 - n ----

	private FldCollection cFlds = new FldCollection();
	public FldCollection getFlds() { return cFlds.clone(); }
	public void addFld(Fld o) { if (o != null) o.setObj((Obj)this); }
	public void removeFld(Fld o) { if (o != null) o.setObj(null); }
	protected void _addFld(Fld o) { cFlds.add(o); }
	protected void _removeFld(Fld o) { cFlds.remove(o); }
	public void addFldDistinct(Fld o) { if (!cFlds.contains(o)) cFlds.add(o); }
	

	private ValueCollection cValues = new ValueCollection();
	public ValueCollection getValues() { return cValues.clone(); }
	public void addValue(Value o) { if (o != null) o.setObj((Obj)this); }
	public void removeValue(Value o) { if (o != null) o.setObj(null); }
	protected void _addValue(Value o) { cValues.add(o); }
	protected void _removeValue(Value o) { cValues.remove(o); }
	public void addValueDistinct(Value o) { if (!cValues.contains(o)) cValues.add(o); }
	

	private IncludeCollection cIncludes = new IncludeCollection();
	public IncludeCollection getIncludes() { return cIncludes.clone(); }
	public void addInclude(Include o) { if (o != null) o.setObj((Obj)this); }
	public void removeInclude(Include o) { if (o != null) o.setObj(null); }
	protected void _addInclude(Include o) { cIncludes.add(o); }
	protected void _removeInclude(Include o) { cIncludes.remove(o); }
	public void addIncludeDistinct(Include o) { if (!cIncludes.contains(o)) cIncludes.add(o); }
	

 

	// --- n - 1 ----

 

	// --- n - n ----
 
	// --- life cycle methods ---
	public void delete() { delete(true); }
	public void delete(boolean ondelete) {
		if (ondelete) this.onDelete();
  		for (Fld o : getFlds()) {
			o.setObj(null);
		}
		for (Value o : getValues()) {
			o.setObj(null);
		}
		for (Include o : getIncludes()) {
			o.setObj(null);
		}
  		d().deleteObj(getId());
 		d()._deleted(this);
	}

	public void onDelete() {} // override 
	public void onLoad(IDomain d) {} // override
	public void onWrite() {} // override
	public void onDeleteEvent() {} // override
	public void onSave() {} // override - not implemented yet
	
	public String toString() {
		String res = "";
		res += nn(name) + ";";
 		res += nn(desc) + ";";
 		res += nn(fname) + ";";
 		res += nn(call) + ";";
  		return res;
	}
	
	
	public final static String[] _flds = {
		"name",
		"desc",
		"fname",
		"call",
   	};
	public static String[] flds() { return _flds; }
	
	public void parseName(String v) {
	    if ("-".equals(v)) v = null;
		setName(v); return;
 	}
	public void parseDesc(String v) {
	    if ("-".equals(v)) v = null;
		setDesc(v); return;
 	}
	public void parseFname(String v) {
	    if ("-".equals(v)) v = null;
		setFname(v); return;
 	}
	public void parseCall(String v) {
	    if ("-".equals(v)) v = null;
		setCall(v); return;
 	}
 
 
 
	// ----- db persistence -----

	protected static String _getSelectFlds() {
		Buffer buf = new Buffer();
		buf.add("id_f,ts,host,vers");
		for (String fld : _flds) {
			buf.add(","+fld+"_f");
		}
		return buf.toString();
	}
	protected String _getUpdateFlds() {
		Buffer buf = new Buffer();
		for (int i = 0; i < _flds.length; i++) {
			if (i > 0) buf.add(",");
			buf.add(_flds[i]+"_f=?");
		}
		return buf.toString();		
	}
	
	protected void _readFlds(Domain d, List row) {
		_modified = row.get(1)==null?null:new Time((java.util.Date)row.get(1));
		String host = (String)row.get(2);
		setVersion((Integer)row.get(3));
		name = (String)row.get(4);
		desc = (String)row.get(5);
		fname = (String)row.get(6);
		call = (String)row.get(7);
   
		// call onLoad
		onLoad(d);
		setVirgin(false);
	}

	
	protected void _writeFlds(DBConnection c) throws Exception {
		onWrite();
		// is it insert or update?
		if (isVirgin()) {
			c.prepare("insert into "+ _tablename+" set id_f=?,host=?,vers=?," + _getUpdateFlds());
			c.param(Long.parseLong(getId()));
			c.param(Domain.getHostName());
			c.param(1L);

			setWriteParams(c);
			
			try {
				c.execute();
			} catch(Exception se) {
				log.error("Failed to insert writeFlds Obj: " + getId());
				throw se;
			}
			setVersion(1L);
		} else {
			c.prepare("update "+ _tablename+" set host=?,vers=?," + _getUpdateFlds() + " where id_f=? AND vers=?");
			c.param(Domain.getHostName());
			c.param(getVersion()+1L); // increment db version
			
			setWriteParams(c);
			
			c.param(Long.parseLong(getId()));
			c.param(getVersion());
			try {
				int res = c.execute();
				if (res != 1) {
					fail("object not found: Obj " + getId() + " " + getVersion());
				}
			} catch(Exception se) {
				log.error("Failed to update writeFlds Obj: " + getId());
				throw se;
			}
			// increment mem object versions when db commit is ok
		}
	}

	private void setWriteParams(DBConnection c) throws Exception {
		c.param(trim(getName(),300));
		c.param(trim(getDesc(),300));
		c.param(trim(getFname(),300));
		c.param(trim(getCall(),300));
   	}

	private final static String _tablename = "obj_t";
	protected String _getTableName() { return _tablename; }

	protected static int _readAllUpdates(Domain d, DBConnection c, Time ts, String host) throws Exception {
		if (host == null) {
			c.prepare("select "+Obj._getSelectFlds()+" from "+_tablename+" where ts >= ?");			
			c.param(ts);
		} else {
			c.prepare("select "+Obj._getSelectFlds()+" from "+_tablename+" where ts >= ? AND host != ?");			
			c.param(ts);
			c.param(host);
		}
		int count = 0;
		for (List row : c.select()) {
			long id = (Integer)row.get(0);
			Obj o = getOrCreate(d,id);
			o._readFlds(d,row);
			count++;
		}
		return count;
	}
	
	private Time _modified;
	public Time getModifiedTime() { return _modified; }
	
	protected static Obj getOrCreate(Domain d, long id) {
		Obj o = d.getObj(id);
		if (o == null) o = d._createEmptyObj(id);
		return o;
	}

}